package com.xuecheng.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.xuecheng.base.model.PageParams;
import com.xuecheng.search.dto.SearchCourseParamDto;
import com.xuecheng.search.dto.SearchPageResultDto;
import com.xuecheng.search.po.CourseIndex;
import com.xuecheng.search.service.CourseSearchService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


@Slf4j
@Service
public class CourseSearchServiceImpl implements CourseSearchService {

    @Value("${elasticsearch.course.index}")
    private String courseIndexStore;
    @Value("${elasticsearch.course.source_fields}")
    private String sourceFields;

    @Autowired
    RestHighLevelClient client;

    /**
     * 分页查询课程发布索引信息，支持关键字搜索、过滤条件、高亮显示及聚合统计
     *
     * @param pageParams           分页参数对象，包含当前页码(pageNo)和每页数量(pageSize)
     * @param courseSearchParam    课程搜索条件参数对象，包含关键字、分类(mt/st)、年级等过滤条件
     * @return SearchPageResultDto<CourseIndex> 分页搜索结果对象，包含数据列表、总数、聚合分类列表等信息
     */
    @Override
    public SearchPageResultDto<CourseIndex> queryCoursePubIndex(PageParams pageParams, SearchCourseParamDto courseSearchParam) {
        // 初始化Elasticsearch搜索请求，指定索引库
        SearchRequest searchRequest = new SearchRequest(courseIndexStore);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        // 设置返回字段白名单（在sourceFields中配置）
        String[] sourceFieldsArray = sourceFields.split(",");
        searchSourceBuilder.fetchSource(sourceFieldsArray, new String[]{});

        // 初始化空搜索条件对象（防御空指针）
        if(courseSearchParam==null){
            courseSearchParam = new SearchCourseParamDto();
        }

        /* 构建关键字多字段匹配查询 */
        if(StringUtils.isNotEmpty(courseSearchParam.getKeywords())){
            MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(
                courseSearchParam.getKeywords(), "name", "description")
                .minimumShouldMatch("70%")  // 设置70%匹配度阈值
                .field("name",10);  // 提升name字段权重
            boolQueryBuilder.must(multiMatchQueryBuilder);
        }

        /* 添加分类过滤条件（精确匹配term查询） */
        if(StringUtils.isNotEmpty(courseSearchParam.getMt())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("mtName",courseSearchParam.getMt()));
        }
        if(StringUtils.isNotEmpty(courseSearchParam.getSt())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("stName",courseSearchParam.getSt()));
        }
        if(StringUtils.isNotEmpty(courseSearchParam.getGrade())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("grade",courseSearchParam.getGrade()));
        }

        /* 设置分页参数 */
        Long pageNo = pageParams.getPageNo();
        Long pageSize = pageParams.getPageSize();
        searchSourceBuilder.from((int) ((pageNo-1)*pageSize));  // 计算起始位置
        searchSourceBuilder.size(Math.toIntExact(pageSize));    // 设置每页数量

        /* 配置高亮显示规则 */
        HighlightBuilder highlightBuilder = new HighlightBuilder()
            .preTags("<font class='eslight'>")  // 高亮前缀标签
            .postTags("</font>")                // 高亮后缀标签
            .field(new HighlightBuilder.Field("name"));  // 指定高亮字段
        searchSourceBuilder.highlighter(highlightBuilder);

        // 组合查询条件并发送搜索请求
        searchSourceBuilder.query(boolQueryBuilder);
        searchRequest.source(searchSourceBuilder);
        buildAggregation(searchRequest);  // 构建聚合查询条件（具体实现在外部）

        /* 执行Elasticsearch查询 */
        SearchResponse searchResponse = null;
        try {
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("课程搜索异常：{}",e.getMessage());
            return new SearchPageResultDto<CourseIndex>(new ArrayList(),0,0,0);
        }

        /* 处理搜索结果数据 */
        SearchHits hits = searchResponse.getHits();
        SearchHit[] searchHits = hits.getHits();
        List<CourseIndex> list = new ArrayList<>();

        // 遍历处理每条命中结果
        for (SearchHit hit : searchHits) {
            // 反序列化基础课程数据
            CourseIndex courseIndex = JSON.parseObject(hit.getSourceAsString(), CourseIndex.class);

            /* 处理高亮字段覆盖 */
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if(highlightFields != null && highlightFields.containsKey("name")){
                HighlightField nameField = highlightFields.get("name");
                // 拼接高亮片段
                StringBuffer stringBuffer = new StringBuffer();
                for (Text fragment : nameField.getFragments()) {
                    stringBuffer.append(fragment.string());
                }
                courseIndex.setName(stringBuffer.toString());
            }

            list.add(courseIndex);
        }

        /* 构建最终返回结果 */
        SearchPageResultDto<CourseIndex> pageResult = new SearchPageResultDto<>(
            list,
            hits.getTotalHits().value,
            pageNo,
            pageSize
        );

        // 添加聚合统计结果（分类树形结构数据）
        pageResult.setMtList(getAggregation(searchResponse.getAggregations(), "mtAgg"));
        pageResult.setStList(getAggregation(searchResponse.getAggregations(), "stAgg"));

        return pageResult;
    }


    private void buildAggregation(SearchRequest request) {
        request.source().aggregation(AggregationBuilders
                .terms("mtAgg")
                .field("mtName")
                .size(100)
        );
        request.source().aggregation(AggregationBuilders
                .terms("stAgg")
                .field("stName")
                .size(100)
        );

    }

    private List<String> getAggregation(Aggregations aggregations, String aggName) {
        // 4.1.根据聚合名称获取聚合结果
        Terms brandTerms = aggregations.get(aggName);
        // 4.2.获取buckets
        List<? extends Terms.Bucket> buckets = brandTerms.getBuckets();
        // 4.3.遍历
        List<String> brandList = new ArrayList<>();
        for (Terms.Bucket bucket : buckets) {
            // 4.4.获取key
            String key = bucket.getKeyAsString();
            brandList.add(key);
        }
        return brandList;
    }
}
